package cn.dream.ebag.MessengerLib.services;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import cn.dream.ebag.MessengerLib.MSCallbackMgr;
import cn.dream.ebag.MessengerLib.WeakReferenceHandler;
import cn.dream.ebag.MessengerLib.constants.MMessageWhat;
import cn.dream.ebag.MessengerLib.constants.MSAction;

import static cn.dream.ebag.MessengerLib.constants.MMParam.PARAM_DATA;

public class MGService extends Service {

    private static final String TAG = "MGService";

    private Messenger serverMessenger;
    private ConcurrentMap<String, Messenger> clientMap;
    private MessengerHandler mHandler;
    public static final int MSG_WHAT_LOCAL_HEARTBEAT = 100;
    public static final int MSG_WHAT_LOCAL_CHECK_CLIENT = 101;

    /**
     * 处理来自客户端的消息，并用于构建Messenger
     */
    private static class MessengerHandler extends WeakReferenceHandler<MGService> {

        public MessengerHandler(MGService weakReference) {
            super(weakReference);
        }

        @Override
        public void handleMessage(MGService instance, Message msg) {
            if (instance == null) {
                return;
            }
            Bundle bundle = msg.getData();
            switch (msg.what) {
                case MMessageWhat.WHAT_CTM_CONNECT:
                    Log.e(TAG, "receive message from client:" + msg.getData().getString("data"));
                    //获取客户端传递过来的Messenger，通过这个Messenger回传消息给客户端
                    if (bundle != null) {
                        String tag = bundle.getString(PARAM_DATA);
                        instance.handleClientConnect(msg.replyTo, tag);
                    }
                    break;
                case MMessageWhat.WHAT_CTM_HEART:
                    Log.d(TAG, "handleMessage: WHAT_CTM_HEART");
                    instance.sendMMessageResponse("heartbeatResponse", MMessageWhat.WHAT_MTC_HEART, msg.replyTo);

                    break;
                case MMessageWhat.WHAT_CTM_JSON:
                    Log.d(TAG, "handleMessage: WHAT_CTM_JSON");
                    if (bundle != null) {
                        String data = bundle.getString(PARAM_DATA);
                        instance.handleClientJsonMsg(msg.replyTo, data);
                    }
                    break;
                case MMessageWhat.WHAT_CTM_ERROR:
                    Log.d(TAG, "handleMessage: WHAT_CTM_ERROR");
                    if (bundle != null) {
                        String data = bundle.getString(PARAM_DATA);
                        instance.handleClientErrorMsg(msg.replyTo, data);
                    }
                    break;
                case MMessageWhat.WHAT_CTM_CLOSE:
                    Log.d(TAG, "handleMessage: WHAT_CTM_CLOSE");
                    if (bundle != null) {
                        String data = bundle.getString(PARAM_DATA);
                        instance.handleClientCloseMsg(data);
                    }
                    break;
                case MSG_WHAT_LOCAL_HEARTBEAT:
                    Log.d(TAG, "handleMessage: MSG_WHAT_LOCAL_HEARTBEAT");
                    if (instance.mHandler != null) {
                        instance.mHandler.sendEmptyMessageDelayed(MSG_WHAT_LOCAL_HEARTBEAT, 10 * 1000);
                    }
                    break;
                default:
                    super.handleMessage(msg);
                    break;
            }
        }

    }


    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate: ");
        init();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (intent != null) {
            handleSendMsgAction(intent);
        }
        return super.onStartCommand(intent, flags, startId);
    }

    private void init() {
        //构建Messenger对象
        mHandler = new MessengerHandler(this);
        serverMessenger = new Messenger(mHandler);
        clientMap = new ConcurrentHashMap<>();
        mHandler.sendEmptyMessage(MSG_WHAT_LOCAL_HEARTBEAT);
    }

    private void handleClientConnect(Messenger clientMessenger, String tag) {
        if (clientMap == null) {
            clientMap = new ConcurrentHashMap<>();
        }
        if (!clientMap.containsKey(tag)) {
            clientMap.put(tag, clientMessenger);
            List<String> clientList = new ArrayList<>(clientMap.keySet());
            MSCallbackMgr.getInstance().sendClientList(clientList);
            MSCallbackMgr.getInstance().sendNewClientMsg(tag);
        }
        //当然，回传消息还是要通过message
        Message message = Message.obtain(null, MMessageWhat.WHAT_MTC_CONNECT);
        Bundle bundle = new Bundle();
        bundle.putString(PARAM_DATA, "hello client, I have received your message!");
        message.setData(bundle);
        try {
            if (clientMessenger != null) {
                clientMessenger.send(message);
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    private void handleClientJsonMsg(Messenger messenger, String jsonMsg) {
        String clientTag = "unKnown";
        if (clientMap != null && messenger != null) {
            Set<String> tagList = clientMap.keySet();
            Log.d(TAG, "handleClientJsonMsg: " + Arrays.toString(tagList.toArray()) + ",jsonMsg=" + jsonMsg);
            for (String tag : tagList) {
                Messenger client = clientMap.get(tag);
                if (client != null && client.hashCode() == messenger.hashCode()) {
                    clientTag = tag;
                    break;
                }
            }
        }
        MSCallbackMgr.getInstance().sendServerJsonMsg(jsonMsg, clientTag);

    }

    private void handleClientErrorMsg(Messenger messenger, String errorMsg) {
        String clientTag = "unKnown";
        if (clientMap != null && messenger != null) {
            Set<String> tagList = clientMap.keySet();
            Log.d(TAG, "handleClientErrorMsg: " + Arrays.toString(tagList.toArray()) + ",errorMsg=" + errorMsg);
            for (String tag : tagList) {
                Messenger client = clientMap.get(tag);
                if (client != null && client.hashCode() == messenger.hashCode()) {
                    clientTag = tag;
                    break;
                }
            }
        }
        MSCallbackMgr.getInstance().sendServerErrorMsg(errorMsg, clientTag);

    }

    /**
     * 处理客户端关闭
     *
     * @param tag
     */
    private void handleClientCloseMsg(String tag) {
        if (TextUtils.isEmpty(tag)) {
            return;
        }
        if (clientMap == null || clientMap.size() < 1) {
            return;
        }
        clientMap.remove(tag);
        handleClientRequest();
    }

    private void handleSendMsgAction(Intent intent) {
        String action = intent.getAction();
        if (TextUtils.isEmpty(action)) {
            return;
        }
        Message message = null;
        String clientTag = intent.getStringExtra("clientTag");
        boolean sendAll = intent.getBooleanExtra("sendAll", false);
        Bundle bundle = new Bundle();
        switch (action) {
            case MSAction.ACTION_SEND_JSON:
                message = Message.obtain(null, MMessageWhat.WHAT_MTC_JSON);
                bundle.putString(PARAM_DATA, intent.getStringExtra(PARAM_DATA));
                break;
            case MSAction.ACTION_SEND_ERROR:
                message = Message.obtain(null, MMessageWhat.WHAT_MTC_ERROR);
                bundle.putString(PARAM_DATA, intent.getStringExtra(PARAM_DATA));
                break;
            case MSAction.ACTION_REQUEST_CONNECTED_CLIENT:
                handleClientRequest();
                break;
            case MSAction.ACTION_CLOSE_CLIENT:
                handleCloseClient(clientTag);
                message = Message.obtain(null, MMessageWhat.WHAT_MTC_CLOSE);
                bundle.putString(PARAM_DATA, "need to close connection");
                break;
            case MSAction.ACTION_CLOSE_SERVER:
                stopSelf();
                break;
            default:
                break;
        }

        if (message != null) {
            message.setData(bundle);
            if (sendAll) {
                sendMMessage2AllClient(message);
                return;
            }
            sendMMessage2SingleClient(message, clientTag);
        }

    }

    private void handleCloseClient(String clientTag) {
        if (clientMap == null || clientMap.size() < 1) {
            return;
        }
        clientMap.remove(clientTag);
        handleClientRequest();
    }

    private void handleClientRequest() {
        List<String> clientList = new ArrayList<>();
        if (clientMap != null && clientMap.size() > 0) {
            clientList.addAll(clientMap.keySet());
        }
        MSCallbackMgr.getInstance().sendClientList(clientList);
    }

    private void sendMMessage2AllClient(Message message) {
        sendMMessage2Client(message, null, true);
    }

    private void sendMMessage2SingleClient(Message message, String tag) {
        sendMMessage2Client(message, tag, false);
    }

    private void sendMMessage2Client(Message message, String clientTag, boolean sendAll) {
        if (clientMap == null || clientMap.size() < 1) {
            return;
        }
        try {
            if (sendAll) {
                Set<String> stringSet = clientMap.keySet();
                for (String key : stringSet) {
                    Messenger client = clientMap.get(key);
                    if (client != null) {
                        client.send(message);
                    }
                }
                return;
            }
            Messenger client = clientMap.get(clientTag);
            if (client != null) {
                client.send(message);
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    private void sendMMessageResponse(String data, int msgWhat, Messenger client) {
        if (client == null) {
            return;
        }
        Message message = new Message();
        message.what = msgWhat;
        Bundle replay = new Bundle();
        replay.putString("data", data);
        message.setData(replay);
        try {
            client.send(message);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind: ");
        if (intent != null) {
            Log.d(TAG, "onBind: intent=" + intent.toString());
            String callingApp = getPackageManager().getNameForUid(Binder.getCallingUid());
            Log.d(TAG, "onBind: callingApp=" + callingApp);
        }
        //将Messenger对象的Binder返回给客户端
        return serverMessenger.getBinder();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.d(TAG, "onUnbind: ");
        if (intent != null) {
            Log.d(TAG, "onUnbind: intent=" + intent.toString());
        }
        stopSelf();
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy: ");
        if (mHandler != null) {
            mHandler.removeCallbacksAndMessages(null);
        }
        if (clientMap != null) {
            clientMap.clear();
        }
        if (serverMessenger != null) {
            serverMessenger = null;
        }
    }
}
